#ifndef BINARIAGEN_CUH
#define BINARIAGEN_CUH

/****************** Representacion binaria ********************/

/******************* Declaracion de Funciones del Host *************************/
void representacionBinariaGen();

void traerImprimirBinariaGen(float* fitnessHost, float* fitnessDevice, int tamVectorFitnessFloat, bool* poblacionHost, bool* poblacionDevice, int tamVectorPoblacion, int iteracion);

/******************* Declaracion de Funciones Global del Device ********************/

__global__ void inicializarPoblacionBinariaGen(bool* poblacion, float* fitnessActualDevice, struct Random randomGPU, int cantCromosomasPoblacion, float* fitnessOrdenadoDevice, unsigned long* numerosAleatoriosInicializacion);
__global__ void mainKernelBinariaGen(bool* poblacionActualDevice, bool* nuevaPoblacionDevice, float* fitnessActualDevice, float* nuevoFitnessDevice, int* poblacionActualAcambiarDevice, int*  nuevaPoblacionAcambiarDevice, float* probabilidadRuletaDevice, float* fitnessTotalParaRuletaDevice, struct Random r, float* fitnessOrdenadoDevice, int* vectorIndicesFitnessOrdenado, unsigned long* numerosAleatoriosSeleccion, unsigned long* numerosAleatoriosCruzamiento, unsigned long* numerosAleatoriosMutacion, unsigned long* numerosAleatoriosProbabilidadCruzamiento, unsigned long* numerosAleatoriosProbabilidadMutacion);

//Estas funciones son global porque es necesario sincronizar los bloques de cada poblacion antes de operar
__global__ void asignarProbabilidadRuletaBinariaGen(float* fitnessActualDevice, float* probabilidadRuletaBinaria, float* fitnessTotalParaRuletaDevice, struct Random randomGPU);

__global__ void migracionRepresentacionBinariaGen(bool* poblacionActualDevice, float* fitnessActualDevice, bool* individuosAMigrarDevice, float* fitnessAMigrarDevice, struct Random randomGPU, bool* individuoAMigrarCPUaGPUdevice, float* fitnessAMigrarCPUaGPUdevice);
__global__ void individuosAMigrarRepresentacionBinariaGen(float* nuevoFitnessDevice, bool* nuevaPoblacionDevice, bool* individuosAMigrarDevice, float* fitnessAMigrarDevice, bool * individuoAMigrarGPUaCPUdevice);

__global__ void reemplazoElitistaSeleccionIndividuosBinariaGen(bool* poblacionActual, bool* nuevaPoblacion, int* poblacionActualAcambiar, int* nuevaPoblacionAcambiar, float * fitnessActual, float* nuevoFitness, int * posIndAreemplazarViejosElitistaGPU, int * posIndAreemplazarNuevosElitistaGPU);
__global__ void reemplazoBinariaGen(bool * poblacionActualDevice, bool * nuevaPoblacionDevice, int * posIndAreemplazarViejosElitistaGPU, int * posIndAreemplazarNuevosElitistaGPU);
__global__ void obtenerMejoresIndividuosBinariaGen(bool* poblacion, float* fitness, bool* mejorIndividuoDevice, float* mejorFitnessIndividuoGPUDevice);
/******************* Declaracion de Funciones internas del Device *****************/
__device__ void obtenerMejorIndividuoBinariaGen(float* vectorFitness, int indices[2]);
__device__ void obtenerPeorIndividuoBinariaGen(float* vectorFitness, int indices[2]);

__device__ int seleccionBinariaGen(float* vectorFitness, float* probabilidadRuletaDevice, struct Random randomGPU, int ejecutarFuncion, int* vectorIndicesFitnessOrdenado, int nroSeleccion);
__device__ int seleccionPorTorneoBinariaGen(float* vectorFitness, struct Random randomGPU, int nroSeleccion);
__device__ int seleccionPorRangoBinariaGen(int* vectorFitness, struct Random randomGPU, int nroSeleccion);
__device__ int seleccionRuedaRuletaBinariaGen(float* probabilidadRuletaDevice, struct Random randomGPU, int nroSeleccion);

__device__ void cruzamientoRepresentacionBinariaGen(bool* poblacionActual, bool* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, struct Random randomGPU, int ejecutarFuncion);
__device__ void cruzamientoCromosoma1PuntoBinariaGen(bool* poblacionActual, bool* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, struct Random randomGPU);
__device__ void cruzamientoCromosoma2PuntosBinariaGen(bool* poblacionActual, bool* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, struct Random randomGPU);
__device__ void cruzamientoCromosomaUniformeBinariaGen(bool* poblacionActual, bool* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, struct Random randomGPU);

__device__ void mutacionBinariaGen(bool* poblacion, float probabilidad, struct Random randomGPU, int ejecutarFuncion);
__device__ void mutacionPorInversionGen(bool* poblacion, float probabilidad, struct Random randomGPU);

__device__ void asignarFitnessBinariaGen(bool* poblacion, float* vectorFitness, float* fitnessOrdenadoDevice);

__device__ void reemplazoElitistaBinariaGen(bool* poblacionActual, bool* nuevaPoblacion, int* arrayParaReemplazoViejo, int* arrayParaReemplazoNuevo);

#endif
